package com.panda.cn.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.panda.cn.config.exception.RestfulException;
import com.panda.cn.entity.SysLoginLogEntity;
import com.panda.cn.entity.SysMenuEntity;
import com.panda.cn.entity.SysUserEntity;
import com.panda.cn.mapper.SysLoginLogMapper;
import com.panda.cn.mapper.SysMenuMapper;
import com.panda.cn.mapper.SysUserMapper;
import com.panda.cn.service.SysLoginLogService;
import com.panda.cn.service.SysUserService;
import com.panda.cn.utils.jwt.JwtUtil;
import com.panda.cn.utils.security.SecureUtil;
import com.panda.cn.utils.userAgent.UserAgentUtil;
import eu.bitwalker.useragentutils.Browser;
import eu.bitwalker.useragentutils.OperatingSystem;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@DS("sys")
public class SysUserServiceImpl implements SysUserService {
    
    @Resource
    private SysUserMapper sysUserMapper;
    
    @Resource
    private SysLoginLogMapper sysLoginLogMapper;
    
    @Resource
    private SysMenuMapper sysMenuMapper;
    
    /**
     * 页面列表
     *
     * @return {@link List}<{@link SysUserEntity}>
     */
    @Override
    public Page<SysUserEntity> pageList(JSONObject params) {
        Long current = params.getLong("current");
        Long size = params.getLong("size");
        log.info("当前页数>>>{}", current);
        log.info("当前页显示数量>>>{}", size);
        Page<SysUserEntity> page = new Page<>(current, size);
        return  sysUserMapper.findPage(page, params);
    }
    
    /**
     * 插入
     *
     * @param params 参数个数
     * @return {@link Long}
     */
    @Override
    public Long insert(SysUserEntity params) {
        // 判断是否为空
        if(StrUtil.isEmpty(params.getName()) || StrUtil.isEmpty(params.getAccount()) || StrUtil.isEmpty(params.getPassword()))
            throw new RestfulException("用户名称或登陆账号或登陆密码不能为空");
        // 查看是不是存在相同的编码和名称
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserEntity::getName, params.getName())
                .or()
                .eq(SysUserEntity::getAccount, params.getAccount());
        Integer count = sysUserMapper.selectCount(queryWrapper);
        if(count>0)
            throw new RestfulException("用户名称或登陆账号存在相同");
        
        // 当前时间
        DateTime nowDateTime = DateUtil.parse(DateUtil.now());
        params.setCreateTime(nowDateTime);
        params.setUpdateTime(nowDateTime);
        // 创建用户uuid
        String code = IdUtil.randomUUID();
        params.setCode(code);
        // 加密密码
        String encryptPassword = SecureUtil.encrypt(params.getPassword());
        params.setPassword(encryptPassword);
        // 添加
        sysUserMapper.insert(params);
        // 添加岗位角色
        sysUserMapper.insertUserJobRole(params);
        return params.getId();
    }
    
    @Override
    public Long update(SysUserEntity params) {
        // 判断是否为空
        if(StrUtil.isEmpty(params.getName()) || StrUtil.isEmpty(params.getAccount()))
            throw new RestfulException("用户名称或登陆账号或登陆密码不能为空");
        // 查看是不是存在相同的编码和名称
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(SysUserEntity::getId, params.getId())
                .and(i -> i.eq(SysUserEntity::getName, params.getName())
                        .or()
                        .eq(SysUserEntity::getAccount, params.getAccount()));
        Integer count = sysUserMapper.selectCount(queryWrapper);
        if(count>0)
            throw new RestfulException("用户名称或登陆账号存在相同");
        
        // 当前时间
        DateTime nowDateTime = DateUtil.parse(DateUtil.now());
        params.setUpdateTime(nowDateTime);
        // 添加
        sysUserMapper.updateById(params);
        // 添加岗位角色
        sysUserMapper.insertUserJobRole(params);
        
        return params.getId();
    }
    
    /**
     * 删除
     *
     * @param params 参数个数
     * @return {@link Long}
     */
    @Override
    public Long remove(List<Long> params) {
        // 验证
        if (ObjUtil.isNull(params) || params.size() == 0)
            throw new RestfulException("唯一编码缺失");
        //  更新的编码
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SysUserEntity::getId, params);
        
        // 更新的数据
        SysUserEntity entity = new SysUserEntity();
        entity.setIsDelete("Y");
        
        int update = sysUserMapper.update(entity, queryWrapper);
        return Long.valueOf(update);
    }
    
    /**
     * 登录
     *
     * @param params 参数个数
     * @return {@link SysUserEntity}
     */
    @Override
    public String login(JSONObject params, HttpServletRequest request) {
        // 验证
        if (ObjUtil.isNull(params) || StrUtil.isEmpty(params.getStr("account"))  || StrUtil.isEmpty(params.getStr("password")))
            throw new RestfulException("登陆账号或密码不能为空");
        // 1、查询账号是否存在
        SysUserEntity entity = sysUserMapper.findLoginUser(params);
        if (ObjUtil.isNull(entity))
            throw  new RestfulException("账号不存在");
        // 2、验证密码
        String password = params.getStr("password");
        // 加密
        String encryptPassword = SecureUtil.encrypt(password);
        if (!encryptPassword.equals(entity.getPassword()))
            throw new RestfulException("密码错误");
        // 创建token
        String token = JwtUtil.createJWT(entity.getAccount(), encryptPassword, entity.getCode());
        
        // 添加登录日志
        SysLoginLogEntity loginLogEntity = new SysLoginLogEntity();
        loginLogEntity.setUserName(entity.getName());
        loginLogEntity.setUserCode(entity.getCode());
        // 当前时间
        DateTime nowDateTime = DateUtil.parse(DateUtil.now());
        // ip地址
        String ip = UserAgentUtil.getIp(request);
        String ipAddress = UserAgentUtil.getIpAddress(ip);
        
        loginLogEntity.setCreateTime(nowDateTime);
        loginLogEntity.setBrowser(UserAgentUtil.getBrowser(request));
        loginLogEntity.setOs(UserAgentUtil.getOs(request));
        loginLogEntity.setIp(ip);
        loginLogEntity.setIpAddress(ipAddress);
        sysLoginLogMapper.insert(loginLogEntity);
        return token;
    }
    
    /**
     * 用户信息
     *
     * @return {@link Map}<{@link String}, {@link Object}>
     */
    @Override
    public SysUserEntity userinfo(String token) {
        String userCode = JwtUtil.getUserId(token);
        JSONObject  params = new JSONObject();
        params.set("code", userCode);
        SysUserEntity sysUserEntity = sysUserMapper.findLoginUser(params);
        String roleCodeStr = sysUserEntity.getRoleCodeStr();
        if (StrUtil.isNotEmpty(roleCodeStr)) {
            String[] roleCodes = roleCodeStr.split(",");
            List<SysMenuEntity> allMenu = sysMenuMapper.findMenuByRoles(roleCodes);
            // 2、数据进行递归查询
            // 获取根部门
            List<SysMenuEntity> treeList = allMenu.stream().filter(menuEntity -> {
                // 全量
                if (ObjUtil.isNotNull(menuEntity) && "root".equals(menuEntity.getParentCode())) {
                    recursion(allMenu, menuEntity);
                    return true;
                }
                return false;
            }).collect(Collectors.toList());
            sysUserEntity.setMenus(treeList);
            
        }
        return sysUserEntity;
    }
    
    
    /**
     * 递归
     *
     * @param allMenu 所有菜单
     * @param entity  实体
     * @return {@link List}<{@link SysMenuEntity}>
     */
    private void recursion(List<SysMenuEntity> allMenu, SysMenuEntity entity) {
        // 要找的数据中 父级菜单的编码
        String code = entity.getCode();
        
        List<SysMenuEntity> childList = allMenu.stream()
                .filter(menuEntity -> {
                    // 有匹配项目
                    if (ObjUtil.isNotNull(menuEntity) && code.equals(menuEntity.getParentCode())) {
                        recursion(allMenu, menuEntity);
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
        if (ObjUtil.isNotNull(childList) && childList.size() > 0)
            entity.setChildren(childList);
    }
    
   
}
